<script lang="ts" setup>
import { ref, watch, onMounted, onUnmounted } from 'vue'

interface IProps {
  width?: number
  visible?: boolean
  height?: number
  refreshIcon?: string
  text?: string
  /**
   * @description 拖拽滑块时的回调, 参数为当前滑块拖拽的距离
   */
  onDraw?: (distance: number) => void
  /**
   * @description 验证失败回调
   */
  onFail?: VoidFunction
  /**
   * @description 刷新时回调
   */
  onRefresh?: VoidFunction
}

const props = withDefaults(defineProps<IProps>(), {
  width: 320,
  visible: true,
  height: 40,
  refreshIcon: 'http://cdn.dooring.cn/dr/icon12.png',
  text: '滑动滑块完成验证',
})

// Define emits with success event that includes timestamp
const emit = defineEmits<{
  (e: 'success', timestamp: number): void
  (e: 'click'): void
}>()

const sliderLeft = ref(0)
const sliderClass = ref('sliderContainer')
const textTip = ref(props.text)
const isMouseDownRef = ref(false)
const startX = ref(0)

const reset = () => {
  sliderLeft.value = 0
  sliderClass.value = 'sliderContainer'
  textTip.value = props.text
  isMouseDownRef.value = false // 确保重置时也清除鼠标按下状态
}

const handleRefresh = () => {
  reset()
  props.onRefresh?.()
}

const verify = () => {
  // Success when slider reaches the end (width - slider width)
  return sliderLeft.value >= props.width - 40
}

const handleDragStart = (e: MouseEvent | TouchEvent) => {
  isMouseDownRef.value = true
  startX.value = sliderLeft.value
  const clientX = e instanceof MouseEvent ? e.clientX : e.touches[0].clientX
  originX.value = clientX
}

const originX = ref(0)

const handleDragMove = (e: MouseEvent | TouchEvent) => {
  if (!isMouseDownRef.value) return

  e.preventDefault()
  const clientX = e instanceof MouseEvent ? e.clientX : e.touches[0].clientX
  const moveX = clientX - originX.value
  const newLeft = startX.value + moveX

  // Constrain the slider within bounds
  sliderLeft.value = Math.max(0, Math.min(newLeft, props.width - 40))

  sliderClass.value = 'sliderContainer sliderContainer_active'
  props.onDraw?.(sliderLeft.value)
}

const handleDragEnd = () => {
  if (!isMouseDownRef.value) return
  isMouseDownRef.value = false

  if (verify()) {
    sliderClass.value = 'sliderContainer sliderContainer_success'
    // Emit success event with current timestamp
    emit('success', Date.now())
  } else {
    sliderClass.value = 'sliderContainer sliderContainer_fail'
    textTip.value = '验证失败，请重试'
    setTimeout(reset, 500)
    props.onFail?.()
  }
}

// Handle mouse/touch events outside the component
const handleGlobalMouseUp = () => {
  if (isMouseDownRef.value) {
    handleDragEnd()
  }
}

// Add global event listeners for better dragging experience
onMounted(() => {
  window.addEventListener('mouseup', handleGlobalMouseUp)
  window.addEventListener('touchend', handleGlobalMouseUp)

  // 初始挂载时确保滑块在初始位置
  if (props.visible) {
    reset()
  }
})

onUnmounted(() => {
  window.removeEventListener('mouseup', handleGlobalMouseUp)
  window.removeEventListener('touchend', handleGlobalMouseUp)
})

watch(
  () => props.visible,
  (newVisible, oldVisible) => {
    // 当组件从隐藏变为显示时，重置滑块位置
    console.log('newVisible, oldVisible', newVisible, oldVisible)
    if (newVisible && newVisible !== oldVisible) {
      reset()
    }
  },
  { deep: true },
)
</script>

<template>
  <div
    class="vertifyWrap"
    :style="{
      width: width + 'px',
    }"
  >
    <div
      :class="sliderClass"
      :style="{
        width: width + 'px',
        height: height + 'px',
      }"
      @mousemove="handleDragMove"
      @mouseup="handleDragEnd"
      @touchmove="handleDragMove"
      @touchend="handleDragEnd"
    >
      <div class="sliderMask" :style="{ width: sliderLeft + 'px' }">
        <div
          class="slider"
          :style="{ left: sliderLeft + 'px' }"
          @mousedown="handleDragStart"
          @touchstart="handleDragStart"
        >
          <div class="sliderIcon unselectable">→</div>
        </div>
      </div>
      <div class="sliderText unselectable">{{ textTip }}</div>
    </div>
    <div
      class="refreshIcon unselectable"
      @click="handleRefresh"
      :style="{ backgroundImage: `url(${refreshIcon})` }"
    ></div>
  </div>
</template>

<style scoped>
.vertifyWrap {
  position: relative;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}

.sliderContainer {
  position: relative;
  text-align: center;
  width: 100%;
  height: 40px;
  line-height: 40px;
  margin-top: 15px;
  background: #f7f9fa;
  color: #45494c;
  border: 1px solid #e4e7eb;
  border-radius: 4px;
  overflow: hidden;
  touch-action: none;
}

.sliderContainer_active .slider {
  height: 38px;
  top: -1px;
  border: 1px solid #486cd6;
  background: #486cd6;
}

.sliderContainer_active .slider .sliderIcon {
  color: white;
}

.sliderContainer_success .slider {
  height: 38px;
  top: -1px;
  border: 1px solid #0db87f;
  background-color: #0ca14a;
}

.sliderContainer_success .sliderMask {
  height: 38px;
  background-color: #d2f4ef;
}

.sliderContainer_success .sliderIcon {
  color: white;
}

.sliderContainer_fail .slider {
  height: 38px;
  top: -1px;
  border: 1px solid #f57a7a;
  background-color: #f57a7a;
}

.sliderContainer_fail .sliderMask {
  height: 38px;
  background-color: #fce1e1;
}

.sliderText {
  z-index: 1;
}

.sliderContainer_active .sliderText,
.sliderContainer_success .sliderText,
.sliderContainer_fail .sliderText {
  display: none;
}

.sliderMask {
  position: absolute;
  left: 0;
  top: 0;
  height: 40px;
  background: #d1e9fe;
  transition: width 0.1s ease;
  z-index: 999;
}

.slider {
  position: absolute;
  top: 0;
  left: 0;
  width: 40px;
  height: 40px;
  background: #fff;
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
  border-radius: 4px;
  cursor: grab;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s ease;
}

.slider:active {
  cursor: grabbing;
}

.slider:hover {
  background: #486cd6;
}

.slider:hover .sliderIcon {
  color: white;
}

.sliderIcon {
  font-size: 18px;
  color: #000;
  pointer-events: none;
}

.refreshIcon {
  position: absolute;
  right: 5px;
  top: 5px;
  width: 30px;
  height: 30px;
  cursor: pointer;
  background-size: 32px;
  background-repeat: no-repeat;
  background-position: center;
}

.unselectable {
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}
</style>
